package com.retail.lottery.colalottery.service.impl;

import com.alibaba.excel.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.retail.lottery.colalottery.constant.ColaHttpUrlConfig;
import com.retail.lottery.colalottery.entity.ProvinceCityAreaInfo;
import com.retail.lottery.colalottery.enums.ErrorCodeEnum;
import com.retail.lottery.colalottery.exception.BadRequestException;
import com.retail.lottery.colalottery.exception.BusinessException;
import com.retail.lottery.colalottery.service.PlatformTenantClientService;
import com.retail.lottery.colalottery.service.ProvinceCityAreaInfoService;
import com.retail.lottery.colalottery.mapper.ProvinceCityAreaInfoMapper;
import com.retail.lottery.colalottery.utils.RestUtils;
import com.retail.lottery.colalottery.vo.response.AccessTokenResponse;
import com.retail.lottery.colalottery.vo.response.ProvinceCityAreaVo;
import lombok.extern.slf4j.Slf4j;
import okhttp3.FormBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
* @author jarvis.zhang
* @description 针对表【province_city_area_info(省市区域信息表)】的数据库操作Service实现
* @createDate 2025-06-23 13:36:21
*/
@Service
@Slf4j
public class ProvinceCityAreaInfoServiceImpl extends ServiceImpl<ProvinceCityAreaInfoMapper, ProvinceCityAreaInfo>
    implements ProvinceCityAreaInfoService{

    @Value("${province-city-area-parentId}")
    private String parentId;
    @Resource
    private RedisTemplate redisTemplate;
    @Value("${api-client-setupId}")
    private String lotterySetupId;
    public static final String provinceCityAreaInfoCacheKey = "provinceCityAreaInfoCacheKey";
    @Resource
    private ColaHttpUrlConfig colaHttpUrlConfig;
    @Resource
    private PlatformTenantClientService platformTenantClientService;


    @Transactional
    @Override
    public Object findAllInfo() {
        //请求可乐省市接口，获取信息
        String provinceCityAreaUrl = colaHttpUrlConfig.getProvinceCityAreaUrl();
        OkHttpClient client = new OkHttpClient().newBuilder()
                .build();
        Request request = new Request.Builder()
                .url(provinceCityAreaUrl)
                .addHeader("Authorization", "Bearer " + platformTenantClientService.getAccessToken(lotterySetupId))
                .build();
        try(Response response = client.newCall(request).execute()){
            if (!response.isSuccessful() || response.body() == null) throw new IOException("Unexpected code " + response);
            List<ProvinceCityAreaVo> areaVos = JSONObject.parseArray(response.body().string(), ProvinceCityAreaVo.class);
            log.info("获取可乐平台获取省市接口返回数据量:{}", areaVos.size());
            // 清理现有表格，数据入库
            List<ProvinceCityAreaInfo> areaInfoList = Lists.newArrayList();
            if (!CollectionUtils.isEmpty(areaVos)) {
                // 从根节点开始递归遍历，层级从1开始
                recursiveConvert(areaVos, 1, areaInfoList);
            }

            if(CollectionUtils.isEmpty(areaInfoList)){
                log.error("请求可乐平台获取省市接口数据为空");
                return new BusinessException(500,"可乐平台获取省市接口数据为空");
            }
            //删除全部数据
            baseMapper.delete(new LambdaQueryWrapper<>());
            this.saveBatch(areaInfoList);
            return areaInfoList.size();
        }catch (Exception e){
            log.error("请求可乐平台获取省市接口异常", e);
            return new BusinessException(500,"获取可乐平台获取省市接口异常");
        }
    }

    private void recursiveConvert(List<ProvinceCityAreaVo> areaVos, int level, List<ProvinceCityAreaInfo> areaInfoList) {
        // 创建ProvinceCityAreaInfo对象并填充数据
        for(ProvinceCityAreaVo areaVo : areaVos){
            ProvinceCityAreaInfo info = new ProvinceCityAreaInfo();
            info.setAreaId(areaVo.getId());
            info.setParentId(areaVo.getParentId());
            info.setName(areaVo.getName());
            info.setLevel(level); // 填充层级信息
            areaInfoList.add(info);

            // 如果有子节点，递归处理子节点，层级加1
            if (!CollectionUtils.isEmpty(areaVo.getChildren())) {
                recursiveConvert(areaVo.getChildren(), level + 1, areaInfoList);
            }
        }
    }

    @Override
    public List<ProvinceCityAreaVo> queryAreaInfo() {
        Object cacheValue = redisTemplate.opsForValue().get(provinceCityAreaInfoCacheKey);
        if(Objects.nonNull(cacheValue) && StringUtils.isNotBlank(cacheValue.toString())){
            return JSONObject.parseArray(cacheValue.toString(), ProvinceCityAreaVo.class);
        }
        List<ProvinceCityAreaInfo> infoList = baseMapper.selectList(new LambdaQueryWrapper<>());
        List<ProvinceCityAreaVo> areaInfoList = Lists.newArrayList();
        return CollectionUtils.isEmpty(infoList) ? areaInfoList : convertToTree(infoList);
    }


    public List<ProvinceCityAreaVo> convertToTree(List<ProvinceCityAreaInfo> infoList) {
        // Create a map for quick lookup of nodes by their ID
        Map<String, ProvinceCityAreaVo> nodeMap = new HashMap<>();

        // First pass: create all nodes and put them in the map
        for (ProvinceCityAreaInfo info : infoList) {
            ProvinceCityAreaVo vo = new ProvinceCityAreaVo();
            vo.setId(info.getAreaId());
            vo.setParentId(info.getParentId());
            vo.setName(info.getName());
            vo.setChildren(new ArrayList<>());
            nodeMap.put(info.getAreaId(), vo);
        }

        List<ProvinceCityAreaVo> roots = new ArrayList<>();
        for (ProvinceCityAreaVo vo : nodeMap.values()) {
            if (Objects.equals(parentId, vo.getParentId())) {
                roots.add(vo);
            } else {
                ProvinceCityAreaVo parent = nodeMap.get(vo.getParentId());
                if (parent != null) {
                    parent.getChildren().add(vo);
                }
            }
        }
        redisTemplate.opsForValue().set(provinceCityAreaInfoCacheKey, JSONObject.toJSONString(roots),30, TimeUnit.MINUTES);

        return roots;
    }


}




